package com.tlgen.tomcat;

import cn.hutool.core.util.StrUtil;
import com.tlgen.tomcat.handler.RequestTask;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class SpeedTomcatApplication {

    public static void main(String[] args) {
        run(args);
    }

    /**
     * 启动 SPeed-Tomcat 服务
     *
     * @throws IOException
     */
    public static void run(String[] args) {
        try {
            String serverPort = System.getProperty("server.port");
            int port = 8890;
            if (StrUtil.isNotBlank(serverPort))
                port = Integer.parseInt(serverPort);

            rowLog(port);

            ServerSocket serverSocket = new ServerSocket(port);

            // 死循环，保证主线程不退出
            while (true) {
                Socket socket = serverSocket.accept();
                createThreadPoolExecutor().execute(new RequestTask(socket));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static ThreadPoolExecutor createThreadPoolExecutor() {
        // 自定义线程池处理
        int corePoolSize = 3;
        int maxPoolSize = 5;
        long queueCapacity = 60L;
        int keepAliveSeconds = 100;

        String corePoolSizeStr = System.getProperty("threadpool.corePoolSize"); // 设置核心线程数量
        String maxPoolSizeStr = System.getProperty("threadpool.maxPoolSize"); // 设置最大线程数量
        String queueCapacityStr = System.getProperty("threadpool.queueCapacity"); // 设置任务队列容量
        String keepAliveSecondsStr = System.getProperty("threadpool.keepAliveSeconds"); // 设置空闲线程存活时间

        if (StrUtil.isNotBlank(corePoolSizeStr))
            corePoolSize = Integer.parseInt(corePoolSizeStr);
        if (StrUtil.isNotBlank(maxPoolSizeStr))
            maxPoolSize = Integer.parseInt(maxPoolSizeStr);
        if (StrUtil.isNotBlank(queueCapacityStr))
            queueCapacity = Integer.parseInt(queueCapacityStr);
        if (StrUtil.isNotBlank(corePoolSizeStr))
            keepAliveSeconds = Integer.parseInt(keepAliveSecondsStr);

        return new ThreadPoolExecutor(
                // 核心线程数
                corePoolSize,
                // 最大线程数
                maxPoolSize,
                // 空闲线程最大存活时间
                queueCapacity,
                // 空闲线程最大存活时间单位
                TimeUnit.SECONDS,
                // 等待队列及大小
                new ArrayBlockingQueue<>(keepAliveSeconds),
                // 创建新线程时使用的工厂
                Executors.defaultThreadFactory(),
                // 当线程池达到最大时的处理策略
                new ThreadPoolExecutor.CallerRunsPolicy() // 交由调用者的线程执行
        );
    }

    private static void rowLog(int port) {
        String rowLog = loadBanner() + loadInfo(port);
        System.out.println(rowLog);
    }

    /**
     * 获取启动 banner 启动图标
     *
     * @return
     */
    private static String loadBanner() {
        return "   ___      ___                      _             _____                                    _     \n" +
                "  / __|    | _ \\   ___     ___    __| |     o O O |_   _|   ___    _ __     __     __ _    | |_   \n" +
                "  \\__ \\    |  _/  / -_)   / -_)  / _` |    o        | |    / _ \\  | '  \\   / _|   / _` |   |  _|  \n" +
                "  |___/   _|_|_   \\___|   \\___|  \\__,_|   TS__[O]  _|_|_   \\___/  |_|_|_|  \\__|_  \\__,_|   _\\__|  \n" +
                "_|\"\"\"\"\"|_| \"\"\" |_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"| {======|_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"| \n" +
                "\" :: SPeed Tomcat :: (v0.0.1)\n\n";
    }

    private static String loadInfo(int port) {
        String name = ManagementFactory.getRuntimeMXBean().getName();
        String PID = name.split("@")[0];
        String mainClassName = getMainClassName();
        String userDir = System.getProperty("user.dir");
        return  String.valueOf(LocalDateTime.now()).replace("T", " ") + "  INFO  " + PID + " --- [           main] " + mainClassName + " : Starting Main on " + System.getenv().get("USERNAME") + " with PID " + PID + " (" + userDir + "\\target\\classes started by " + System.getenv().get("USERNAME") + " in " + userDir + ")\n" +
                String.valueOf(LocalDateTime.now()).replace("T", " ") + "  INFO  " + PID + " --- [           main] " + mainClassName + " : No active profile set, falling back to default profiles: default\n" +
                String.valueOf(LocalDateTime.now()).replace("T", " ") + "  INFO  " + PID + " --- [           main] com.tlgen.SpeedTomcatApplication  : Tomcat initialized with port(s): " + port + " (http)\n" +
                String.valueOf(LocalDateTime.now()).replace("T", " ") + "  INFO  " + PID + " --- [           main] com.tlgen.SpeedTomcatApplication.[SPeed-Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext\n" +
                String.valueOf(LocalDateTime.now()).replace("T", " ") + "  INFO  " + PID + " --- [           main] com.tlgen.WebServerApplicationContext : Root WebApplicationContext: initialization completed in 2366 ms\n" +
                String.valueOf(LocalDateTime.now()).replace("T", " ") + "  INFO  " + PID + " --- [           main] java.util.concurrent.ThreadPoolExecutor  : Initializing ExecutorService 'applicationTaskExecutor'\n" +
                String.valueOf(LocalDateTime.now()).replace("T", " ") + "  INFO  " + PID + " --- [           main] com.tlgen.SpeedTomcatApplication  : SPeed-Tomcat started on port(s): " + port + " (http) with context path ''\n" +
                String.valueOf(LocalDateTime.now()).replace("T", " ") + "  INFO  " + PID + " --- [           main] " + mainClassName + " : Started Main in 3.829 seconds (JVM running for 5.138)";
    }

    private static String getMainClassName() {
        return  new SecurityManager() {
            public String getClassName() {
                return getClassContext()[1].getName();
            }
        }.getClassName();
    }

}